//
//  CSCyclingRouteViewControllerHealth.swift
//  Cycling
//
//  Created by CSS on 4/18/23.
//

import Foundation
import UIKit
import HealthKit
import YYKit

//健康相关的处理
extension NSObject {
    
    private struct AssociatedObject {
        
        static var healthStore: Int = 0
        
    }
    
    private var healthStore: HKHealthStore {
        get {
            if let healthStore = objc_getAssociatedObject(self, &AssociatedObject.healthStore) as? HKHealthStore {
                return healthStore
            }
            let healthStore = HKHealthStore()
            objc_setAssociatedObject(self, &AssociatedObject.healthStore, healthStore, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            return healthStore
        } set {
            objc_setAssociatedObject(self, &AssociatedObject.healthStore, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    @objc func requestHeartDatas(from fromDate: Date?, toDate: Date?, complete:((Bool, CyclingRouteHeartModel?) -> Void)?) {
        if !HKHealthStore.isHealthDataAvailable() {
            complete?(false, nil)
            return
        }
//        if !healthStore.supportsHealthRecords() {
//            complete?(false, nil)
//            return
//        }
        guard let fromDate = fromDate, let toDate = toDate else {
            complete?(false, nil)
            return
        }
        guard let quantityType = HKQuantityType.quantityType(forIdentifier: .heartRate) else {
            //不支持该类型
            complete?(false, nil)
            return
        }
        let predicate = NSPredicate(format: "startDate >= %@ and endDate <= %@", fromDate as CVarArg, toDate as CVarArg)

        healthStore.getRequestStatusForAuthorization(toShare: [], read: [quantityType]) { [weak self]status, error in
            if status == .shouldRequest {
                //用户还没有授权，不能获取数据
                DispatchQueue.main.async {
                    complete?(false, nil)
                }
                return
            }
            self?.requestHeartDatas(withPredicate: predicate, complete: complete)
        }
    }
    
    private func requestHeartDatas(withPredicate predicate: NSPredicate, complete:((Bool, CyclingRouteHeartModel?) -> Void)?) {
        guard let sampleType = HKSampleType.quantityType(forIdentifier: .heartRate) else {
            //不支持该类型
            complete?(false, nil)
            return
        }
        
        let quantitySample = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [.init(key: HKSampleSortIdentifierStartDate, ascending: true)]) { sampleQuery, samples, error in
            if error != nil {
                complete?(false, nil)
                return
            }
            guard let heartSamples = samples as? [HKQuantitySample], heartSamples.count > 0 else {
                //没有找到合适的数据
                complete?(false, nil)
                return
            }
            var xs: [String] = []
            var datas: [Double] = []
            let dateFormat = DateFormatter()
            dateFormat.dateFormat = "HH:mm"
            for heartSample in heartSamples {
                xs.append(dateFormat.string(from: heartSample.startDate))
                datas.append(heartSample.quantity.doubleValue(for: HKUnit(from: "count/min")))
            }
            let detailModel = CyclingRouteHeartModel()
            detailModel.unit = "count/min"
            detailModel.x = xs
            detailModel.data = datas.reduce([], { $0 + [NSNumber(value: $1)] })
            complete?(true, detailModel)
        }
        healthStore.execute(quantitySample)
    }
    
    
    /**
     返回值说明:第一个表示是否获取权限，第二个表示如果没有权限，是否需要跳转Health App
     */
    @objc func requestHealthAppAuthorization(onComplete complete:((Bool, Bool) -> Void)?) {
        if !HKHealthStore.isHealthDataAvailable() {
            complete?(false, false)
            return
        }
        guard let heartType = HKQuantityType.quantityType(forIdentifier: .heartRate), let sleepType = HKQuantityType.categoryType(forIdentifier: .sleepAnalysis) else {
            //不支持该类型
            complete?(false, false)
            return
        }
        healthStore.getRequestStatusForAuthorization(toShare: [], read: [heartType, sleepType], completion: { status, error in
            DispatchQueue.main.async {
                if status == .shouldRequest {
                    self.healthStore.requestAuthorization(toShare: nil, read: [heartType, sleepType]) { success, error in
                        DispatchQueue.main.async {
                            complete?(success, false)
                        }
                    }
                    return
                }
                complete?(false, true)
            }
        })
    }
    
    @objc func checkShouldShowPermissionPromt(onComplete complete:((Bool) -> Void)?) {
        if !HKHealthStore.isHealthDataAvailable() {
            complete?(false)
            return
        }
        guard let heartType = HKQuantityType.quantityType(forIdentifier: .heartRate), let sleepType = HKQuantityType.categoryType(forIdentifier: .sleepAnalysis) else {
            //不支持该类型
            complete?(false)
            return
        }
        healthStore.getRequestStatusForAuthorization(toShare: [], read: [heartType, sleepType], completion: { status, error in
            DispatchQueue.main.async {
                complete?(status == .shouldRequest)
            }
        })
    }
    
    @objc func showHealthPermissionPromot(onComplete complete:((Bool) -> Void)?) {
        if !HKHealthStore.isHealthDataAvailable() {
            complete?(false)
            return
        }
        guard let heartType = HKQuantityType.quantityType(forIdentifier: .heartRate), let sleepType = HKQuantityType.categoryType(forIdentifier: .sleepAnalysis) else {
            //不支持该类型
            complete?(false)
            return
        }
        healthStore.requestAuthorization(toShare: nil, read: [heartType, sleepType]) { success, error in
            DispatchQueue.main.async {
                complete?(success)
            }
        }
    }
    
}

//首页面发送健康的数据
extension NSObject {
    
    @objc func postHealthDataToServer(fromDate: Date? = .distantPast, endDate: Date? = .distantFuture) {
        if !HKHealthStore.isHealthDataAvailable() {
            return
        }
        guard let fromDate = fromDate, let endDate = endDate else {
            return
        }
        guard let quantityType = HKQuantityType.quantityType(forIdentifier: .heartRate), let sleepType = HKQuantityType.categoryType(forIdentifier: .sleepAnalysis) else {
            //不支持该类型
            return
        }
        let predicate = NSPredicate(format: "startDate >= %@ and endDate <= %@", fromDate as CVarArg, endDate as CVarArg)
        
        healthStore.getRequestStatusForAuthorization(toShare: [], read: [quantityType, sleepType]) { [weak self]status, error in
            if status == .shouldRequest {
                //用户还没有授权，不能获取数据
                return
            }
            self?.postHealthDataToServer(withPredicate: predicate)
        }
    }
    
    private func postHealthDataToServer(withPredicate predicate: NSPredicate) {
        guard let heartSampleType = HKSampleType.quantityType(forIdentifier: .heartRate), let sleepSampleType = HKSampleType.categoryType(forIdentifier: .sleepAnalysis) else {
            return
        }
        var heartRequestComplete = false
        var sleetRequestComplete = false
        var heartDatas: [[String:Any]] = []
        var sleepDatas: [[String:Any]] = []
        let heartQuery = HKSampleQuery(sampleType: heartSampleType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [.init(key: HKSampleSortIdentifierStartDate, ascending: true)]) { sampleQuery, samples, error in
            if error != nil {
                heartRequestComplete = true
                if sleetRequestComplete {
                    self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
                }
                return
            }
            guard let heartSamples = samples as? [HKQuantitySample], heartSamples.count > 0 else {
                //没有找到合适的数据
                heartRequestComplete = true
                if sleetRequestComplete {
                    self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
                }
                return
            }
            heartDatas = heartSamples.reduce([], {
                let date = $1.startDate.timeIntervalSince1970
                return $0 + [["start" : date, "value" : $1.quantity.doubleValue(for: .init(from: "count/min"))]]
            })
            heartRequestComplete = true
            if sleetRequestComplete {
                self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
            }
        }
        
        let sleepQuery = HKSampleQuery(sampleType: sleepSampleType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [.init(key: HKSampleSortIdentifierStartDate, ascending: true)]) { sampleQuery, results, error in
            if error != nil {
                sleetRequestComplete = true
                if heartRequestComplete {
                    self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
                }
                return
            }
            
            guard let sleepSamples = results as? [HKCategorySample], sleepSamples.count > 0 else {
                //没有找到合适的数据
                sleetRequestComplete = true
                if heartRequestComplete {
                    self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
                }
                return
            }
            /**
            type 0=卧床 1=睡眠 2=清醒时间 3=核心睡眠 4=深度睡眠 5=快速眼动睡眠
             */
            let fixSleepSamples = sleepSamples.reduce(into: [HKCategorySample]()) { partialResult, currentSample in
                if currentSample.value == 2 {
                    return
                }
                if partialResult.count == 0 {
                    partialResult.append(currentSample)
                    return
                }
                let lastSample = partialResult.last!
                if (lastSample.value == 0 && currentSample.value != 0) || (lastSample.value != 0 && currentSample.value == 0) {
                    partialResult.append(currentSample)
                    return
                }
                if !Calendar.current.isDate(lastSample.startDate, inSameDayAs: currentSample.startDate) {
                    partialResult.append(currentSample)
                    return
                }
                if currentSample.startDate > lastSample.endDate {
                    if currentSample.startDate.timeIntervalSince(lastSample.startDate) < 5 * 60 {
                        partialResult[partialResult.count - 1] = .init(type: lastSample.categoryType, value: lastSample.value, start: lastSample.startDate, end: currentSample.endDate)
                    } else {
                        partialResult.append(currentSample)
                    }
                    return
                }
                partialResult[partialResult.count - 1] = .init(type: lastSample.categoryType, value: lastSample.value, start: lastSample.startDate, end: max(currentSample.endDate, lastSample.endDate))
            }
            sleepDatas = fixSleepSamples.reduce([], {
                $0 + [["start" : $1.startDate.timeIntervalSince1970, "end" : $1.endDate.timeIntervalSince1970, "type" : ($1.value == 0 ? 0 : 1)]]
            })
            
//            DispatchQueue.main.async {
//                if #available(iOS 15.0, *) {
//                    let resultString = fixSleepSamples.reduce("", {
//                        $0 + "start:\($1.startDate.formatted(date: .abbreviated, time: .standard)), end: \($1.endDate.formatted(date: .abbreviated, time: .standard))\n"
//                    })
//                    UIPasteboard.general.string = resultString
//                    HUDHelper.showHudTipStr("复制成功")
//                }
//            }
//            sleepSamples.forEach { sample in
//                print("sample:\(sample)")
//            }
            sleetRequestComplete = true
            if heartRequestComplete {
                self.postHealthDataToServer(withHeartDatas: heartDatas, sleepDatas: sleepDatas)
            }
        }
        
        healthStore.execute(heartQuery)
        healthStore.execute(sleepQuery)
    }
    
    private func postHealthDataToServer(withHeartDatas heartDatas: [[String: Any]], sleepDatas: [[String:Any]]) {
        if heartDatas.count < 0 && sleepDatas.count < 0 {
            return
        }
        guard let jsonString = (["heart" : heartDatas, "sleep" : sleepDatas] as NSDictionary).modelToJSONString() else {
            return
        }
        print("jsonString: \(jsonString)")
        HealthDataRequest.addHealthDataToServer(withParams: jsonString)
    }
    
}
